package com.tnxst.phexamination.utils;

import com.tnxst.phexamination.dto.TCMHealthDTO;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class ReflectUtils {


    public static <T> T mapToObject(Map<String, Object> map,T obj) {
        if (map == null || obj == null)
            return null;
        Map<String,Object> newMap = new LinkedHashMap<>();

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey().toUpperCase();
            Object value = entry.getValue();
            newMap.put(key,value);
        }
        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if(Modifier.isStatic(mod) || Modifier.isFinal(mod)){
                    continue;
                }

                String name = field.getName().toUpperCase();

                if (!newMap.containsKey(name))
                    continue;
                Object o = newMap.get(name);
                if (field.getType() == Integer.class){
                    Integer v = null;
                    if (o instanceof Double){
                        v = Double.valueOf(o.toString()).intValue();
                    }else {
                        if (o != null)
                            v = Integer.valueOf(o.toString());
                    }
                    field.setAccessible(true);
                    field.set(obj, v);
                    continue;
                }
                field.setAccessible(true);
                if (o instanceof Double){
                    if (field.getType() == String.class)
                        field.set(obj, String.valueOf(Double.valueOf(o.toString()).intValue()));
                    else
                        field.set(obj, Double.valueOf(o.toString()).intValue());
                    continue;
                }
                field.set(obj, newMap.get(name));
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public static<T> T mapToObject(Map<String, Object> map, Class<T> beanClass) {
        if (map == null)
            return null;

        Map<String,Object> newMap = new LinkedHashMap<>();

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey().toUpperCase();
            Object value = entry.getValue();
            newMap.put(key,value);
        }
        Object obj = null;
        try {
            obj = beanClass.newInstance();
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if(Modifier.isStatic(mod) || Modifier.isFinal(mod)){
                    continue;
                }
                String name = field.getName().toUpperCase();

                if (!newMap.containsKey(name))
                    continue;
                Object o = newMap.get(name);
                if (field.getType() == Integer.class){
                    Integer v = null;
                    if (o instanceof Double){
                        v = Double.valueOf(o.toString()).intValue();
                    }else {
                        if (o != null)
                            v = Integer.valueOf(o.toString());
                    }
                    field.setAccessible(true);
                    field.set(obj, v);
                    continue;
                }
                field.setAccessible(true);
                if (o instanceof Double){
                    if (field.getType() == String.class)
                        field.set(obj, String.valueOf(Double.valueOf(o.toString()).intValue()));
                    else
                        field.set(obj, Double.valueOf(o.toString()).intValue());
                    continue;
                }
                if (o instanceof Map)
                    o = GsonUtils.toJson(o);
                field.set(obj, o);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return (T) obj;
    }

    public static Map<String, Object> objectToMap(Object obj){
        if(obj == null){
            return null;
        }

        Map<String, Object> map = new HashMap<String, Object>();
        try {
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                if (StringUtils.isNotNull(field.get(obj)))
                    map.put(field.getName(), field.get(obj));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return map;
    }

    public static Map<String, Object> objectToMap(String[] names, Object obj, Map map){
        if (obj == null || names.length == 0)
            return null;
        if (map == null)
            map = new HashMap();
        try {
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                if (StringUtils.isNotNull(field.get(obj)) && isExist(names,field.getName()))
                    map.put(field.getName(), field.get(obj));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return map;
    }

    private static boolean isExist(String[] names, String field){
        if (field == null)
            return false;
        for (String name : names) {
            if (field.equals(name))
                return true;
        }
        return false;
    }

    public static boolean setFiledByFiledName(Object obj, String filedName, Object value){
        if (obj == null || StringUtils.isNull(filedName) || value == null)
            return false;
        Class<?> clazz = obj.getClass();
        try {
            Field declaredField = clazz.getDeclaredField(filedName);
            if (declaredField == null)
                return false;
            declaredField.setAccessible(true);
            declaredField.set(obj,value);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static Object getFiledByFiledName(Object obj, String filedName) {
        if (obj == null || StringUtils.isNull(filedName))
            return null;
        Class<?> clazz = obj.getClass();
        try {
            Field declaredField = clazz.getDeclaredField(filedName);
            if (declaredField == null)
                return null;
            declaredField.setAccessible(true);
            return declaredField.get(obj);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}
